#pragma once

#include "OMIT_MeshForwardDecl.h"

namespace OMIT_NAMESPACE
{
	template<bool PtrConst, typename Traits>
	class H_NextView
        : public MeshViewBase<H_NextView<PtrConst, Traits>, 
                              MeshTraits_PH<PtrConst, Traits>,
                              MeshTraits_PH<PtrConst, Traits>>
	{
		using PH = MeshTraits_PH<PtrConst, Traits>;
		friend MeshViewBase<H_NextView<PtrConst, Traits>, PH, PH>;
		static PH Value(PH ph) { return ph; }
		static PH Next(PH ph) { return ph->Next(); }
	public:
		using MeshViewBase<H_NextView<PtrConst, Traits>, PH, PH>::MeshViewBase;
	};

	template<bool PtrConst, typename Traits>
	class H_RotaView
        : public MeshViewBase<H_RotaView<PtrConst, Traits>,
                              MeshTraits_PH<PtrConst, Traits>,
                              MeshTraits_PH<PtrConst, Traits>>
	{
		using PH = MeshTraits_PH<PtrConst, Traits>;
		friend MeshViewBase<H_RotaView<PtrConst, Traits>, PH, PH>;
		static PH Value(PH ph) { return ph; }
		static PH Next(PH ph) { return ph->RotateNext(); }
	public:
		using MeshViewBase<H_RotaView<PtrConst, Traits>, PH, PH>::MeshViewBase;
	};

	template<typename Traits>
	MeshTraits_H<Traits>* TMesh_H<Traits>::Pre() noexcept {
		auto* h = this;
		auto* next = h->Next();
		do {
			h = next;
			next = h->Next();
		} while (next != this);
		return h->PThis();
	}

	template<typename Traits>
	void TMesh_H<Traits>::Init(TH* next, TH* pair, TV* v, TE* e, TF* f) noexcept {
		assert(next != nullptr && pair != nullptr && v != nullptr && e != nullptr);
		this->_next = next;
		this->_pair = pair;
		_origin = v;
		_edge = e;
		_face = f;
	}

	template<typename Traits>
	void TMesh_H<Traits>::Reset() noexcept {
		_next = nullptr;
		_pair = nullptr;
		_origin = nullptr;
		_edge = nullptr;
		_face = nullptr;
	}

	template<typename Traits>
	MeshTraits_H<Traits>* TMesh_H<Traits>::FindFreeIncident(TH* begin, TH* end) {
		assert(begin->End() == end->End());

		for (auto* h = begin; h != end; h = h->Next()->Pair()) {
			if (h->IsFree())
				return h->PThis();
		}

		return nullptr;
	}

	template<typename Traits>
	bool TMesh_H<Traits>::MakeAdjacent(TH* begin, TH* end) {
		assert(begin->End() == end->Origin());

		if (begin->Next() == end)
			return true;

		auto* freeIn = FindFreeIncident(end->Pair(), begin);
		if (freeIn == nullptr)
			return false;

		auto* inNext = begin->Next();
		auto* outPre = end->Pre();
		auto* freeInNext = freeIn->Next();

		begin->SetNext(end);
		freeIn->SetNext(inNext);
		outPre->SetNext(freeInNext);

		return true;
	}

	template<typename Traits>
	std::size_t TMesh_H<Traits>::FaceDegree() const noexcept {
		std::size_t cnt = 0;
		for (const auto& h : NextLoop())
			++cnt;
		return cnt;
	}
}
